package com.authine.cloudpivot.ext.service.account.impl;

import cn.hutool.core.map.MapBuilder;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.exception.framework.BaseException;
import com.authine.cloudpivot.ext.Enum.TradeDirection;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.finance.AccountDto;
import com.authine.cloudpivot.ext.dto.model.trade.Trade;
import com.authine.cloudpivot.ext.dto.system.OrganizationDto;
import com.authine.cloudpivot.ext.service.account.AccountService;
import com.authine.cloudpivot.ext.utils.BigDecimalUtils;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.cloudpivot.ext.utils.RegexUtils;
import com.authine.cloudpivot.ext.utils.system.OrgUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class AccountServiceImpl implements AccountService {

    @Override
    public AccountDto loadById(String id) {
        AccountDto accountDto = JdbcTemplateUtils.builder(ModelConst.T_ACCOUNT).selectField("*")
                .eq("id", id)
                .queryForPOJO(AccountDto.class);
        Assert.notNull(accountDto, "结算账户不存在");
        return accountDto;
    }

    @Override
    public List<AccountDto> loadListByIds(List<String> ids) {
        List<AccountDto> accountDtos = JdbcTemplateUtils.builder(ModelConst.T_ACCOUNT).selectField("*")
                .in("id", ids)
                .queryForPOJOList(AccountDto.class);
        return accountDtos;
    }

    @Override
    public void update(AccountDto accountDto) {
        //加载更新前的账户
        AccountDto beforeAccount = JdbcTemplateUtils.builder(ModelConst.T_ACCOUNT).selectField("*")
                .eq("id", accountDto.getId())
                .queryForPOJO(AccountDto.class);
        Assert.notNull(beforeAccount, "修改账户不存在");

        //更新账户信息
        MapBuilder<String, Object> builder = MapBuilder.create(new HashMap<String, Object>())
                .put("id", accountDto.getId())
                .put("account_balance",accountDto.getAccount_balance())
                .put("credit_limit", accountDto.getCredit_limit())
                .put("available_limit", accountDto.getAvailable_limit())
                .put("bonus", accountDto.getBonus())
                .put("platform_rate", accountDto.getPlatform_rate())
                .put("other_rate", accountDto.getOther_rate())
                .put("service_rate", accountDto.getService_rate());

        SingleResponse<BO> response = BoServiceUtils.updateMainBo(ModelConst.T_ACCOUNT,builder.build());
        Assert.isTrue(response.isSuccess(), "修改账户失败");

        //对比修改字段
        MapBuilder<String, Object> accountRecord = MapBuilder.create(new HashMap<String, Object>())
                .put("account_id", accountDto.getId())
                .put("memo", accountDto.getMemo());
        //比对余额
        int balance = accountDto.getAccount_balance().compareTo(beforeAccount.getAccount_balance());
        if(balance!=0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","accountBalance");
            accountRecord.put("old_value", beforeAccount.getAccount_balance());
            accountRecord.put("new_value", accountDto.getAccount_balance());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对信用额度
        int credit = accountDto.getCredit_limit().compareTo(beforeAccount.getCredit_limit());
        if(credit != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","credit_limit");
            accountRecord.put("old_value", beforeAccount.getCredit_limit());
            accountRecord.put("new_value", accountDto.getCredit_limit());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对可用额度
        int available = accountDto.getAvailable_limit().compareTo(beforeAccount.getAvailable_limit());
        if(available != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","available_limit");
            accountRecord.put("old_value", beforeAccount.getAvailable_limit());
            accountRecord.put("new_value", accountDto.getAvailable_limit());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对积分
        int bonus = accountDto.getBonus().compareTo(accountDto.getBonus());
        if(bonus != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","bonus");
            accountRecord.put("old_value", accountDto.getBonus());
            accountRecord.put("new_value", accountDto.getBonus());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对平台费率
        int platformRate = accountDto.getPlatform_rate().compareTo(beforeAccount.getPlatform_rate());
        if(platformRate != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","platform_rate");
            accountRecord.put("old_value", beforeAccount.getPlatform_rate());
            accountRecord.put("new_value", accountDto.getPlatform_rate());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对服务费率
        int serviceRate = accountDto.getService_rate().compareTo(beforeAccount.getService_rate());
        if(serviceRate != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","service_rate");
            accountRecord.put("old_value", beforeAccount.getService_rate());
            accountRecord.put("new_value", accountDto.getService_rate());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
        //比对其他费率
        int otherRate = accountDto.getOther_rate().compareTo(beforeAccount.getOther_rate());
        if(otherRate != 0){
            accountRecord.map().remove("id");//防止多次插入主键ID重复
            accountRecord.put("column_name","other_rate");
            accountRecord.put("old_value", beforeAccount.getOther_rate());
            accountRecord.put("new_value", accountDto.getOther_rate());
            accountRecord.put("memo",accountDto.getMemo());
            BoServiceUtils.createBo(ModelConst.T_ACCOUNT_RECORD, Collections.singletonList(accountRecord.build()));
        }
    }

    public Boolean saveByTrades(List<Trade> tradeList) {
        List<Trade> trades = new ArrayList<>();
        for (Trade trade : tradeList) {
            trades.add(
                    Trade.builder()
                            .id(trade.getId())
                            .amount(trade.getAmount())
                            .direction(trade.getDirection())
                            .organization_id(trade.getOrganization_id())
                            .platform_organization_id(trade.getPlatform_organization_id())
                            .order_goods_id(trade.getOrder_goods_id())
                            .build());
        }
        //获取交易组织
        List<OrganizationDto> tradeOrganizationList = OrgUtils.getOrgListByOrgIds(trades.stream().map(t -> t.getOrganization_id().getId()).collect(Collectors.toList()));
        //获取交易组织对应的结算组织
        List<OrganizationDto> tranOrganizationList = this.getTranOrganization(tradeOrganizationList);
        List<String> tranAccountIds = tranOrganizationList.stream().filter(t -> null != t.getAccount_id()).map(OrganizationDto::getAccount_id).collect(Collectors.toList());
        List<AccountDto> tradeAccountList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(tranAccountIds)) {
            tradeAccountList.addAll(loadListByIds(tranAccountIds));
        }

        //获取平台组织
        List<OrganizationDto> platformOrganizationList = OrgUtils.getOrgListByOrgIds(trades.stream().map(t -> t.getPlatform_organization_id().getId()).collect(Collectors.toList()));
        //获取平台组织的结算组织
        List<OrganizationDto> tranPlatformOrganizationList = this.getTranOrganization(platformOrganizationList);

        List<String> platformAccountIds = tranPlatformOrganizationList.stream().filter(t -> null != t.getAccount_id()).map(OrganizationDto::getAccount_id).collect(Collectors.toList());
        List<AccountDto> platformAccountList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(platformAccountIds)) {
            platformAccountList.addAll(loadListByIds(platformAccountIds));
        }

        Map<String, AccountDto> updateAccountMap = new HashMap<>();
        for (Trade trade : trades) {

            OrganizationDto data = tradeOrganizationList.stream().filter(t -> t.getId().equals(trade.getOrganization_id().getId())).findAny().get();
            if (trade.getDirection().equals(TradeDirection.Sale.name())) {
                //客户组织对应的结算组织id
                //客户结算组织id对应的accountId
                String cAccountId = tranOrganizationList.stream().filter(t -> t.getId().equals(data.getTransaction_organization_id().get(0).getId())).findFirst().get().getAccount_id();

                //平台组织对应的结算组织id
                String pTrId = platformOrganizationList.stream().filter(t -> t.getId().equals(trade.getPlatform_organization_id().getId()))
                        .findFirst().orElseThrow(IllegalArgumentException::new).getTransaction_organization_id().get(0).getId();
                String pAccountId = tranPlatformOrganizationList.stream().filter(t -> t.getId().equals(pTrId)).findFirst().orElseThrow(IllegalArgumentException::new).getAccount_id();

                //平台销售 增加
                AccountDto pAccount = platformAccountList.stream().filter(t -> t.getId().equals(pAccountId)).findFirst().orElse(null);
                Assert.notNull(pAccount, "请联系平台客服添加平台结算账户！");

                if (updateAccountMap.containsKey(pAccountId)) {
                    pAccount = updateAccountMap.get(pAccountId);
                } else {
                    updateAccountMap.put(pAccountId, pAccount);
                }

                BigDecimal creditLimit = null == pAccount.getCredit_limit() ? BigDecimal.ZERO : pAccount.getCredit_limit();
                pAccount.setCredit_limit(BigDecimalUtils.add(creditLimit, trade.getAmount()));

                //客户 减少
                AccountDto cAccount = tradeAccountList.stream().filter(t -> t.getId().equals(cAccountId)).findFirst().orElse(null);
                Assert.notNull(cAccount, "请联系平台客服为["+trade.getOrganization_id().getId()+"]添加结算账户");

                if (updateAccountMap.containsKey(cAccountId)) {
                    cAccount = updateAccountMap.get(cAccountId);
                } else {
                    updateAccountMap.put(cAccountId, cAccount);
                }

                creditLimit = null == cAccount.getCredit_limit() ? BigDecimal.ZERO : cAccount.getCredit_limit();
                cAccount.setCredit_limit(BigDecimalUtils.sub(creditLimit, trade.getAmount()));
            } else if (trade.getDirection().equals(TradeDirection.Purchase.name())) {
                //供应商组织对应的结算组织id
                //供应商结算组织id对应的accountId
                String vAccountId = tranOrganizationList.stream().filter(t -> t.getId().equals(data.getTransaction_organization_id().get(0).getId())).findFirst().orElseThrow(IllegalArgumentException::new).getAccount_id();

                //平台组织对应的结算组织id
                String pTrId = platformOrganizationList.stream().filter(t -> t.getId().equals(trade.getPlatform_organization_id().getId())).findFirst().orElseThrow(IllegalArgumentException::new)
                        .getTransaction_organization_id().get(0).getId();
                String pAccountId = tranPlatformOrganizationList.stream().filter(t -> t.getId().equals(pTrId)).findFirst().get().getAccount_id();

                //平台采购 减少
                AccountDto pAccount = platformAccountList.stream().filter(t -> t.getId().equals(pAccountId)).findFirst().orElse(null);
                Assert.notNull(pAccount, "请联系平台客服为["+pTrId+"]添加结算账户");

                if (updateAccountMap.containsKey(pAccountId)) {
                    pAccount = updateAccountMap.get(pAccountId);
                } else {
                    updateAccountMap.put(pAccountId, pAccount);
                }

                BigDecimal creditLimit = null == pAccount.getCredit_limit() ? BigDecimal.ZERO : pAccount.getCredit_limit();
                pAccount.setCredit_limit(BigDecimalUtils.sub(creditLimit, trade.getAmount()));

                //供应商 增加
                AccountDto vAccount = tradeAccountList.stream().filter(t -> t.getId().equals(vAccountId)).findFirst().orElse(null);
                Assert.notNull(vAccount, "请联系平台客服为["+trade.getOrganization_id().getId()+"]添加结算账户");

                if (updateAccountMap.containsKey(vAccountId)) {
                    vAccount = updateAccountMap.get(vAccountId);
                } else {
                    updateAccountMap.put(vAccountId, vAccount);
                }

                creditLimit = null == vAccount.getCredit_limit() ? BigDecimal.ZERO : vAccount.getCredit_limit();
                vAccount.setCredit_limit(BigDecimalUtils.add(creditLimit, trade.getAmount()));
            }
        }
        updateAccountMap.forEach((key, value) -> update(value));
        return true;
    }
    private List<OrganizationDto> getTranOrganization(List<OrganizationDto> organizationList) {
        List<OrganizationDto> results = new ArrayList<>();
        Set<String> tranOrganizationIds = new HashSet<>();
        for (OrganizationDto organization : organizationList) {
            if (organization.getId().equals(organization.getTransaction_organization_id().get(0).getId())) {
                results.add(organization);
            } else {
                tranOrganizationIds.add(organization.getTransaction_organization_id().get(0).getId());
            }
        }
        if (!CollectionUtils.isEmpty(tranOrganizationIds)) {
            List<OrganizationDto> tranOrganizationList = OrgUtils.getOrgListByOrgIds(new ArrayList<>(tranOrganizationIds));
            results.addAll(tranOrganizationList);
        }
        return results;
    }
}
